package db

import (
	"fmt"
	"log"
	"os"
	"project1/config"
	"project1/dbmodel"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

var (
	GormDB *gorm.DB
	err    error
)

// 初始化数据库及表
func Init() {
	fmt.Println("db init")
	InitMysqlDB(
		config.Conf,
		[]any{"用户", new(dbmodel.User)},           //用户
		[]any{"卡密表", new(dbmodel.Carmine)},       //卡密表
		[]any{"网站基础配置", new(dbmodel.BaseConfig)}, //网站基础配置
	)
	//初始化数据
	InitDbData()
	//表字段添加、修改、删除、索引等操作
	TableColumnModify()
}

// InitMysqlDB 初始化mysql
func InitMysqlDB(dbConf config.ConfStruct, models ...[]any) {
	fmt.Printf("yaml配置文件数据:%+v\n", dbConf)
	loggers := logger.Info
	if dbConf.DB.SqlLogger {
		loggers = logger.Error
	}
	masterConf := dbConf.DB
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", masterConf.User, masterConf.Password, masterConf.Host, masterConf.Port, masterConf.Name)
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
		logger.Config{
			SlowThreshold:             5 * time.Second, // 慢 SQL 阈值, 5s
			LogLevel:                  loggers,         // Log level
			IgnoreRecordNotFoundError: false,           //是否忽略 record not found 错误，这里不忽略
			ParameterizedQueries:      false,           // Don't include params in the SQL log
			Colorful:                  true,            // Disable color
		},
	)
	GormDB, err = gorm.Open(mysql.New(mysql.Config{
		DSN:                       dsn,
		DefaultStringSize:         25,    //string 类型字段的默认长度
		DisableDatetimePrecision:  true,  //禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,  //重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,  //用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false, //根据当前 MySQL 版本自动配置
	}), &gorm.Config{
		CreateBatchSize: 100, //默认批量创建的大小
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true, //使用单数表名，启用该选项后，`User` 表将是`user`
		},
		// Logger: logger.Default.LogMode(logger.Error),
		Logger: newLogger,
	})
	if err != nil {
		panic("connect database failed:" + err.Error())
	}
	for _, sliceValue := range models {
		tableName := sliceValue[0].(string)
		err = GormDB.Set("gorm:table_options", "COMMENT='"+tableName+"'").AutoMigrate(sliceValue[1])
		if err != nil {
			panic("database table genete failed" + err.Error())
		}
	}
	DB, err := GormDB.DB()
	if err != nil {
		panic("DB database failed" + err.Error())
	}
	// SetMaxIdleConns 设置空闲连接池中连接的最大数量
	DB.SetMaxIdleConns(10)
	// SetMaxOpenConns 设置打开数据库连接的最大数量
	DB.SetMaxOpenConns(100)
	// SetConnMaxLifetime 设置了连接可复用的最大时间
	DB.SetConnMaxLifetime(time.Second * 40)
	DB.Ping()
}

// InitDbData 初始化数据
func InitDbData() {
}

// TableColumnModify 表字段添加、修改、删除、索引等操作
func TableColumnModify() {
	//用gorm的迁移功能，不一定会把表字段修改掉(有些会改，暂时不知道什么逻辑)，但用AlterColumn一定会把表字段修改掉
	//GormDB.Migrator().AlterColumn(&dbmodel.PaymentProduct{}, "PublicKey")

	// merchantOrder := dbmodel.MerchantOrder{}
	// if !GormDB.Migrator().HasIndex(&merchantOrder, "idx_external_status_createdat") {
	// 	GormDB.Exec("create index idx_external_status_createdat on merchant_order(`external_id`,`status`,`created_at`);")
	// }
}

// 检查数据库数据
func InitCheckSql() {
	sn := 1
	// 死循环检测sn是否为0，直到sn为0时，才结束死循环
	for sn != 0 {
		sn, err := CheckSqlInitData() // 检查数据库初始数据是否完整
		if sn == 0 {
			break
		}

		if err != nil {
			fmt.Printf("\n检查数据库数据完整性出错,Err:%s sn:%d\n", err.Error(), sn)

			// 开始一个新的事务
			tx := GormDB.Begin()
			if sn == 1 {
				println("开始创建超级管理员账号")
				// 创建超级管理员账号
				user, err := CreateUserP1("", "", "", "", "", 1, 0, 0, 0)
				if err != nil {
					tx.Rollback() // 事务回滚
					fmt.Printf("\n创建超级管理员账号出错,Err:%s\n", err.Error())
					os.Exit(1)
				}

				err = tx.Create(&user).Error
				if err != nil {
					tx.Rollback() // 事务回滚
					fmt.Printf("\n创建超级管理员账号出错,Err:%s\n", err.Error())
					os.Exit(1)
				}
			}

			if sn == 2 {
				println("开始创建管理员账号")
				// 创建管理员账号
				user, err := CreateUserP1("", "admin", "123456", "", "", 2, 0, 1, 0)
				if err != nil {
					tx.Rollback() // 事务回滚
					fmt.Printf("\n创建管理员账号出错,Err:%s\n", err.Error())
					os.Exit(1)
				}

				err = tx.Create(&user).Error
				if err != nil {
					tx.Rollback() // 事务回滚
					fmt.Printf("\n创建管理员账号出错,Err:%s\n", err.Error())
					os.Exit(1)
				}
			}

			// 提交事务
			if err := tx.Commit().Error; err != nil {
				fmt.Printf("\n提交事务出错,Err:%s\n", err.Error())
				os.Exit(1)
			} else {
				println("创建账号成功")
			}

		}
	}

	fmt.Println("\n-----------检查数据库完成-----------\n")
}
